package com.zmn.oms.task.job.perf;

import com.github.ltsopensource.core.domain.Action;
import com.github.ltsopensource.core.domain.Job;
import com.github.ltsopensource.spring.tasktracker.JobRunnerItem;
import com.github.ltsopensource.spring.tasktracker.LTS;
import com.github.ltsopensource.tasktracker.Result;
import com.google.common.collect.Lists;
import com.zmn.common.dto.ResultDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.oms.business.interfaces.perf.PerfDimensionBService;
import com.zmn.oms.business.interfaces.perf.PerfFactBService;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.entity.perf.PerfDimensionDistribute;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 描述: 绩效定时任务
 *
 * @author HanKangShuai
 * @date 2019-7-2
 **/
@LTS
@Slf4j
public class PerfDistributeJob {

    private static final int SINGLE_SYNC_SIZE = 500;

    public static final int PARTITION_SIZE = 10;

    @Resource
    TaskManager taskManager;
    @Resource
    PerfFactBService<PerfDimensionDistribute> perfDistributeFactBService;
    @Resource
    PerfDimensionBService<PerfDimensionDistribute> perfDistributeDimensionBService;

    /**
     * 派单绩效定时任务初始化
     */
    @PostConstruct
    public void submitDistributeJob() {
        Job job = new Job();
        job.setTaskId(TaskConsts.TASK_ID_PERF_DISTRIBUTE);
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_PERF_DISTRIBUTE);
        // 每小时一次
        job.setCronExpression("0 0 0/1 * * ? *");
        job.setReplaceOnExist(true);
        ResultDTO result = taskManager.submitTask(job);
        if (!result.getStatusBool()) {
            log.error("#perf#distribute#每小时定时任务提交失败");
        }
        job.setTaskId(TaskConsts.TASK_ID_PERF_DISTRIBUTE_DAY);
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_PERF_DISTRIBUTE_DAY);
        // 每日3:10一次
        job.setCronExpression("0 10 3 1/1 * ? ");
        ResultDTO resultB = taskManager.submitTask(job);
        if (!resultB.getStatusBool()) {
            log.error("#perf#distribute#每日定时任务提交失败");
        }
    }

    /**
     * 描述: 运行派单绩效每小时任务
     *
     * @param job 任务
     * @return com.github.ltsopensource.tasktracker.Result
     **/
    @JobRunnerItem(shardValue = TaskConsts.TASK_ID_PERF_DISTRIBUTE)
    public Result runPerfDistributeHourJob(Job job) {
        Supplier<List<PerfDimensionDistribute>> allDimensionSupplier = perfDistributeDimensionBService.getAllDimensionSupplier();
        List<PerfDimensionDistribute> distributes = allDimensionSupplier.get();

        int updateCount = Lists.partition(distributes, PARTITION_SIZE)
                .stream()
                .mapToInt(partitionList -> perfDistributeFactBService.syncFact(partitionList, LocalDate.now()))
                .sum();

        String fromStr = job.getParam("from");
        String toStr = job.getParam("to");
        if (fromStr != null) {
            log.info("[派单绩效] 统计区间【{}】-【{}】", fromStr, toStr);
            LocalDate from = LocalDate.parse(fromStr);
            LocalDate to = LocalDate.parse(toStr);
            int sum = Stream.iterate(from, localDate -> localDate.plusDays(1L))
                    .limit(ChronoUnit.DAYS.between(from, to) + 1)
                    // 把每天换成每天的同步结果
                    .mapToInt(localDate -> perfDistributeFactBService.syncFact(distributes, localDate))
                    // 把每天的同步结果转换成日志
                    .sum();
        }
        return new Result(Action.EXECUTE_SUCCESS, "执行成功了!");
    }

    /**
     * 描述: 运行派单绩效每日任务
     *
     * @param job 任务
     * @return com.github.ltsopensource.tasktracker.Result
     **/
    @JobRunnerItem(shardValue = TaskConsts.TASK_ID_PERF_DISTRIBUTE_DAY)
    public Result perfDistributeDayJob(Job job) {
        int intervalLength = Optional.ofNullable(job.getParam("intervalLength")).map(Integer::parseInt).orElse(90);
        log.debug("#perf#distribute#开始同步今日前{}天至今日的派单绩效", intervalLength);

        // 同步一次纬度
        Integer syncDimensionUpdate = perfDistributeDimensionBService.syncDimension();
        log.debug("#perf#distribute#派单员纬度更新了{}条", syncDimensionUpdate);
        Supplier<List<PerfDimensionDistribute>> allDimensionSupplier = perfDistributeDimensionBService.getAllDimensionSupplier();
        List<PerfDimensionDistribute> distributes1 = allDimensionSupplier.get();
        log.debug("#perf#distribute#本次同步将要同步的派单员：{}", distributes1.stream().map(PerfDimensionDistribute::getDistributorId).collect(Collectors.toList()));
        LocalDate to = LocalDate.now();
        int sum = 0;
        for (int i = 0; i < intervalLength; i++) {
            LocalDate currentDate = to.minusDays(i);
            Integer count = perfDistributeFactBService.syncFact(distributes1, currentDate);
            sum += count;
            log.debug("#perf#distribute#同步[{}]的派单绩效成功|更新数据[{}]|总进度[{}]", currentDate, count, NumberUtil.divAndToPercent(i + 1, intervalLength));
        }
        log.debug("#perf#distribute#同步完成,共更新了{}条数据", sum);
        return new Result(Action.EXECUTE_SUCCESS, String.format("同步完成,共更新了%d条数据", sum));
    }
}
